package IceAssembly;


/**
 *  <html>
 *    <head>
 *      
 *    </head>
 *    <body>
 *      <p style="margin-top: 0">
 * Instruction processor that makes decisions based on the instruction being a 
 * pseudo-op or a regular instruction, and performs checks and other 
 * considerations to ensure that labels, parameters, and operations and 
 * functions are all correct and can be added to the tables for the assembly 
 * of the pass1 intermediate file to be used further in the program.
 *      </p>
 *    </body>
 *  </html>
 */
public class Process {
    Table table_instance = new Table();
    Check check_instance = new Check();
    SubProcess sub_process_instance = new SubProcess();
    Initialize init_instance = new Initialize();
    Convert convert_instance = new Convert();
    Control control_instance = new Control();
    
    /**
     * Determines whether the instruction was a mnemonic instruction, or a 
     * directive/pseudo-op and then takes makes the appropriate action to have 
     * those processed accordingly.<p>
     * Tokened_string[]
         *  Index 0 : code - 0/1 - (0-no label, 1-label)
         *  Index 1 : label if any
         *  Index 2 : Mnemonic or directive
         *  Index 3 : function or (function or operands)
         *  Index 4 : comma if any
         *  Index 5 : operands for mnemonic if any
     * <p>
     * <b>Change Log:</b><br>
     * April 14 - Documented function - Peter<br>
     * April 16 - Changed role to be controller for mnemonics and directives and 
     * implemented function - Peter<br>
     * <p>
     * <b>Error Conditions Tested:</b><br>
     * 100 - Invalid instruction, substituting MOPER ADD,0<br>
     * 200 - Invalid label <br>
     * <p>
     * <b>Error Messages Generated:</b><br>
     * <INSERT EACH ERROR MESSAGE GENERATED> <br>
     * <p>
     * <b>Date of module being installed:</b> 4/14/08
     * <p><b>Original Author:</b>  Peter Dietz
     * @param tokened_string String array that has code, label, mnem, func, param.  See above.
     */
    public int processInstruction (String[] tokened_string){
        /*  Tokened_string[]
         *  Index 0 : code - 0/1 - (0-no label, 1-label)
         *  Index 1 : label if any
         *  Index 2 : Mnemonic or directive
         *  Index 3 : function or (function or operands)
         *  Index 4 : comma if any
         *  Index 5 : operands for mnemonic if any
         */
        if (tokened_string[0].contentEquals("1")){//contains a label.            
            if (check_instance.isValidLabel(tokened_string[1])==0){//Invalid syntactically or pre defined
                if(table_instance.addToErrorTable("104")==0){
                    return 1000;//fatal error more than 3072 errors.
                }
                tokened_string[0]="0";
                tokened_string[1]="";
            }
            if (check_instance.isValidLabel(tokened_string[1])==2){//in symbol table
                if(table_instance.addToErrorTable("205")==0){
                    return 1000;//fatal error more than 3072 errors.
                }
                tokened_string[0]="0";
                tokened_string[1]="";
            }
        }
        if(Control.line_num == 0 || tokened_string[2].toUpperCase().compareTo("START")==0){
            return sub_process_instance.processStart(tokened_string);            
        }        
        if(tokened_string[2].toUpperCase().compareTo("END")==0){
            return sub_process_instance.processEnd(tokened_string);
        }
        
        if(check_instance.isMnemonic(tokened_string[2]) == 1){
            return processMnemonic(tokened_string);
        }else if(check_instance.isPseudoOP(tokened_string[2]) == 1){
            return processPseudoOp(tokened_string);
        }else{//substitute moper add,0
            if(table_instance.addToErrorTable("100")==0){
                return 1000;//fatal error more than 3072 errors.
            }
            if(table_instance.addToIntermediateFile("11000", "00000000000", "A") == 0){
                return 2000;//fatal error more than 1024 memory words.
            }
            Control.location_counter++;
            return 50;
        }
    }

    /**
     * Processes the mnemonic instruction by checking that it is valid, and 
     * finds the binary code for the instruction-function pairing. Also the 
     * label required will be checked and the parameters will be checked that 
     * they are correct. Additionally, the instruction is added to the 
     * intermediate file, symbol table, and error table if neccessary.
     * <p>
     * <b>Change Log:</b><br>
     * April 16 - Added operation and documented it - Peter<br>
     * April 18 - changed how we receive info with getInfoForMnemonic - Peter<br>
     * <p>
     * <b>Error Conditions Tested:</b><br>
     * 101 - Mnemonic and function pair not found, substitute MOPER ADD,0<br>
     * <p>
     * <b>Date of module being installed:</b> April 16
     * <p><b>Original Author:</b>  Peter Dietz
     * @param tokened_string String array that has code, label, mnem, func, param
     * @return success of operation. 1 is success, 0 is fail
     */    
    public int processMnemonic (String[] tokened_string) {        
        String[] info = init_instance.getInfoForMnemonicPair(tokened_string[2], tokened_string[3]);
        /* info[]
         * Index 0 - code - 0/1 - (0-pair not found and 1-pair found)
         * Index 1 - binary - 5bits
         * Index 2 - operands 0/1/2/3 - (0=none, 1=rlabel, 2=nn, 3=binary_label)
         * Index 3 - relocation possibilities - a, r, e, c
        */
        if(info[0].contentEquals("0")){
            // 101 - Mnemonic and function pair not found, substituting MOPER ADD,0
            if(table_instance.addToErrorTable("101")==0){
                return 1000;//fatal error - more than 3072 errors.
            }
            if(table_instance.addToIntermediateFile("11000", "00000000000", "A") == 0){
                return 2000;//fatal error - more than 1024 memory words.
            }
            Control.location_counter++;
            return 50;//proceed to next line
        }
        if(tokened_string[0].contentEquals("1")){
            if(table_instance.addToSymbolTable(tokened_string[1], "label", "-")==0){
                if(table_instance.addToErrorTable("112")==0){
                    return 3000;
                }
            }
        }
        int status = processMnemonicParameter(info[1], info[2], tokened_string[4], tokened_string[5]);
        if(status==50){            
            Control.location_counter++;
        }
        return status;
    }
    
    /**
     * Processes pseudo-op from assembly code does validation for errors in the 
     * label and operands. Fetches the binary code for instructions if needed. 
     * Adds labels or other directives to the symbol table, and determines if
     * the instruction consumed memory, and increments the location_counter. 
     * Lastly it adds the instruction to the intermediate_file or error_table if
     * neccessary.
     * <p>
     * Change Log:<br>
     * April 14 - Documented function - Peter<br>
     * April 16 - Changed return type to string array - Peter<br>
     * <p>
     * Error Conditions Tested:<br>
     * <INSERT EACH CONDITION TESTED> <br>
     * <p>
     * Error Messages Generated: <br>
     * <INSERT EACH ERROR MESSAGE GENERATED> <br>
     * <p>
     * Date of module being installed: 4/14/08
     * @param tokened_string String array that has code, label, mnem, func, param
     * @return The success of the operation. 1 is success, and 0 is failure
     */        
    public int processPseudoOp (String[] tokened_string) {                
        String[] info = init_instance.getInfoForPseudoOp(tokened_string[2]);
        /* info[]
         * Index 0 = code - 0/1
         * Index 1 = length
         * Index 2 = operand format
         * Index 3 = label_number (0,1,2) not number of labels
        */        
        if(tokened_string[2].toUpperCase().contentEquals("END")){
            return sub_process_instance.processEnd(tokened_string);            
        }
        if(info[3].contentEquals("0")){
            if(tokened_string[0].contentEquals("0")){//no label found when required                
                if(table_instance.addToErrorTable("107")==0){
                    return 1000;
                }
                return 50;//line ignored so don't increment location counter
            }
        }
        if(info[3].contentEquals("2")){
            if(tokened_string[0].contentEquals("1")){//found a label when not required
                table_instance.addToErrorTable("212");
            }
            tokened_string[0] = "0"; //label ignored        
        }
        if(tokened_string[4].compareTo(",")==0){//found a comma in pseudo-op                        
            if(table_instance.addToErrorTable("157")==0){
                return 1000;
            }           
            if(table_instance.addToIntermediateFile("00000", "00000000000", "A") == 0){//dat i=0
                return 2000;//fatal error more than 1024 memory words
            }
            if(tokened_string[0].contentEquals("1")){
                if(table_instance.addToSymbolTable(tokened_string[1], "dat", "-")==0){
                    if(table_instance.addToErrorTable("112")==0){
                        return 3000;
                    }
                    return 50;
                }
            }
            return 50;
        }        
        int value = processPseudoOpParameters(info[2],tokened_string[3],tokened_string[1]);                
        return value;//don't know the use of this return statement
    }
   
    /**
     * This function process the Pseudo-Op Parameters, checks for error and add them to error table.<br>
     * <p>
     * <b>Change Log:</b><br>
     * <DATE> <REASON - WHAT YOU DID> <USER> <br>
     * <p>
     * <b>Error Conditions Tested:</b><br>
     * <INSERT EACH CONDITION TESTED> <br>
     * <p>
     * <b>Error Messages Generated:</b><br>
     * <INSERT EACH ERROR MESSAGE GENERATED> <br>
     * <p>
     * <b>Date of module being installed:</b> <INSERT DATE HERE>
     * @param parameter_info - Contains the type of parameter
     * @param parameter - Contains the parameter
     * @return int : to be added
     */
    private int processPseudoOpParameters(String parameter_info, String parameter, String label){
        
        if(parameter_info.compareTo("")==0){//means no operands...
        }
        if(parameter_info.compareTo("nn")==0){
            if(sub_process_instance.processAlln(parameter_info,parameter)==2){
                if((Control.location_counter+Integer.parseInt(parameter))<1024){
                    Control.location_counter+=Integer.parseInt(parameter);
                }else{
                    table_instance.addToErrorTable("115");
                }
            }else{
                table_instance.addToErrorTable("150");
            }
        }else if(parameter_info.compareTo("nmax")==0){
            if(sub_process_instance.processAlln(parameter_info,parameter)==2){
                
            }else{
                table_instance.addToErrorTable("151");
            }
        }else if(parameter_info.compareTo("resetoperand")==0){
            Other.Reset reset_instance = new Other.Reset();
            return reset_instance.processReset(label, parameter);
        }else if(parameter_info.compareTo("adcoperand")==0){
            Other.Adc adc_instance = new Other.Adc();
            return adc_instance.processAdc(label,parameter);
        }else if(parameter_info.compareTo("nmax or elabel")==0){
            Other.Equ equ_instance = new Other.Equ();
            return equ_instance.processEqu(label, parameter);
        }else if(parameter_info.compareTo("rlabel1")==0){
            if(parameter.contentEquals("")||parameter.contentEquals(" ")){
                if(table_instance.addToErrorTable("159")==0){
                    return 1000;//fatal error more than 3072 errors
                }
                return 50;//no parameter
            }
            int value = check_instance.isValidLabel(parameter);
            if(value==0||value==2){//syntactically incorrect or previously defined.
                if(table_instance.addToErrorTable("159")==0){
                    return 1000;//fatal error more than 3072 errors
                }
                return 50;
            }else{
                String[] all_exvar = table_instance.getAllLabels("SHVAR");
                if(!all_exvar[0].contentEquals("0")){                
                    for(int index=1; index<all_exvar.length; index++){
                        if(parameter.contentEquals(all_exvar[index])){
                            if(table_instance.addToErrorTable("159")==0){
                                return 1000;//fatal error more than 3072 errors
                            }
                            return 50;
                        }
                    }
                }
                if(table_instance.addToSymbolTable(parameter, "EXVAR", "-")==0){
                    return 3000;
                }
                return 50;
            }
        }else if(parameter_info.compareTo("rlabel2")==0){
            if(parameter.contentEquals("")||parameter.contentEquals(" ")){
                if(table_instance.addToErrorTable("160")==0){                   
                    return 1000;//fatal error more than 3072 errors
                }
                return 50;//no parameter
            }
            int value = check_instance.isValidLabel(parameter);
            if(value==0){//syntactically incorrect
                if(table_instance.addToErrorTable("160")==0){
                    return 1000;//fatal error more than 3072 errors
                }
                return 50;
            }else{
                String[] all_shvar = table_instance.getAllLabels("SHVAR");
                if(!all_shvar[0].contentEquals("0")){                
                    for(int index=1; index<all_shvar.length; index++){
                        if(parameter.contentEquals(all_shvar[index])){
                            if(table_instance.addToErrorTable("160")==0){
                                return 1000;//fatal error more than 3072 errors
                            }
                            return 50;
                        }
                    }
                }
                String[] all_exvar = table_instance.getAllLabels("EXVAR");
                if(!all_exvar[0].contentEquals("0")){                
                    for(int index=1; index<all_exvar.length; index++){
                        if(parameter.contentEquals(all_exvar[index])){
                            if(table_instance.addToErrorTable("160")==0){
                                return 1000;//fatal error more than 3072 errors
                            }
                            return 50;
                        }
                    }
                }
                if(table_instance.addToSymbolTable(parameter, "SHVAR", "-")==0){
                    return 3000;
                }
                return 50;
            }
        }
        else if(parameter_info.compareTo("option")==0){
            if(parameter.toUpperCase().compareTo("ON")==0){
                Control.debug_status = "ON";
            }else if(parameter.toUpperCase().compareTo("OFF")==0){
                Control.debug_status = "OFF";
            }else{
                table_instance.addToErrorTable("152");
            }
        }else if(parameter_info.compareTo("program_name")==0){            
        }else if(parameter_info.compareTo("S=")==0){
            String temp = sub_process_instance.processPseudoLiterals(parameter);
            if(temp.contentEquals("0")){
                if(table_instance.addToErrorTable("158")==0){
                    return 1000;//fatal error more than 3072 errors
                }
                if(table_instance.addToIntermediateFile("00000", "00000000000", "A") == 0){                    
                    return 2000;//fatal error more than 1024 memory words
                }
                if(label.contentEquals("")){
                    return 50;
                }
                if(table_instance.addToSymbolTable(label, "dat", "-")==0){
                    return 3000;
                }                
            }else{
                if(table_instance.addToIntermediateFile(temp.substring(0,5), temp.substring(5), "A") == 0){
                    return 2000;//fatal error more than 1024 memory words
                }
                if(label.contentEquals("")){
                    return 50;
                }
                if(table_instance.addToSymbolTable(label, "dat", "-")==0){
                    return 3000;
                }
            }
            Control.location_counter++;
            return 50;
        }else if(parameter_info.compareTo("FORMULA")==0){
            if(parameter.contentEquals("")){
                if(table_instance.addToErrorTable("162")==0){//no operand
                    return 1000;//fatal error more than 3072 errors
                }
            }else{
                int value = sub_process_instance.processComp(label,parameter);
                return value;
            }
        }
        return 0;
    }
    
    /**
     * Checks that the parameter is valid for the parameter type, including checks 
     * that it is of the valid range for that type. Additionally this operation 
     * shall try to determine the relocation_type if it can by eliminating choices
     * that would be invalid. Adds to error table if it found errors, and corrects
     * parameters to a default value if they were incorrect for their type.
     * <p>
     * Change Log:<br>
     * April 14 - Documented function - Peter<br>
     * April 18 - Changed parameters to help with mnemonics and pseudo-ops - Peter
     * May 11 - Blank parameter checked and corresponding error thrown - Yogesh Jindal.
     * May 11 - Error 103 removed from documentation, No longer checked by this function. - Yogesh Jindal
     * <p>
     * Error Conditions Tested:<br>
     * 102 - expected parameters, but none were present<br>     
     * 104 - not a valid label syntactically<br>
     * 105 - Operand was not in valid range for nn<br>
     * 106 - Operand was not in valid range for binary label<br>
     * 201 - expected no parameters, but received parameters<br>
     * 202 - Instruction required comma for seperator character<br>
     * 203 - Instruction required no seperator character<br>
     * <p>
     * Date of module being installed: April 14
     * <p><b>Original Author:</b>  Peter Dietz
     * @param parameter_info information representing type of parameter
     * @param op_code The machine operation code to be processed
     * @param separator Seperation character between operation-function and operand
     * @param parameter Parameters to the instruction or psuedo-op
     * @return Processing parameters completed successfully 1, 0 if error in parameters
     */    
    public int processMnemonicParameter(String op_code, String parameter_info, String separator, String parameter){        
        if(parameter_info.contentEquals("none")){
            if(separator.compareTo(",")==0){
                if(table_instance.addToErrorTable("201")==0){
                    return 1000;//fatal error more than 3072 errors.
                }
            }
            if(table_instance.addToIntermediateFile(op_code, "00000000000", "A") == 0){//cntl halt
                return 2000;//fatal error more than 1024 memory words.
            }
            return 50;
        }
        if(!separator.contentEquals(",")){
            if(table_instance.addToErrorTable("113")==0){
                return 1000;//fatal error more than 3072 errors.
            }
            if(table_instance.addToIntermediateFile("11000", "00000000000", "A") == 0){
                return 2000;//fatal error more than 1024 memory words.                
            }
            return 50;
        }
        if(parameter.contentEquals("")){
            if(table_instance.addToErrorTable("102")==0){
                return 1000;//fatal error more than 3072 errors.
            }
            if(table_instance.addToIntermediateFile("11000", "00000000000", "A") == 0){
                return 2000;//fatal error more than 1024 memory words.                
            }
            return 50;
        }
        if(parameter_info.contentEquals("binary5")){
            String temp_value = sub_process_instance.processBinary5(parameter);
            if(temp_value.contentEquals("0")){
                if(table_instance.addToErrorTable("106")==0){
                    return 1000;//fatal error more than 3072 errors.
                }
                if(table_instance.addToIntermediateFile("11000", "00000000000", "A") == 0){//moper add,0
                    return 2000;//fatal error more than 1024 memory words
                }
                return 50;
            }else{
                if(table_instance.addToIntermediateFile(op_code, "0"+temp_value, "A") == 0){
                    return 2000;//fatal error more than 1024 memory words
                }
                return 50;
            }
        }else if(parameter_info.contentEquals("binary4")){
            String temp_value = sub_process_instance.processBinary4(parameter);
            if(temp_value.contentEquals("0")){
                if(table_instance.addToErrorTable("114")==0){
                    return 1000;//fatal error more than 3072 errors.
                }
                if(table_instance.addToIntermediateFile("11000", "00000000000", "A") == 0){//moper add,0
                    return 2000;//fatal error more than 1024 memory words
                }
                return 50;
            }else{
                if(table_instance.addToIntermediateFile(op_code, "0"+temp_value, "A") == 0){//moper add,0
                    return 2000;//fatal error more than 1024 memory words
                }
                return 50;
            }
        }else if(parameter_info.contentEquals("nn")){
            int temp_value = sub_process_instance.processAlln(parameter_info, parameter);
            if(temp_value!=2){//not in range or a non-integer.
                if(table_instance.addToErrorTable("105")==0){
                    return 1000;//fatal error more than 3072 errors.
                }
                if(table_instance.addToIntermediateFile("11000", "00000000000", "A") == 0){//moper add,0
                   return 2000;//fatal error more than 1024 memory words.                
                }
                return 50;
            }else{//in range
                if(table_instance.addToIntermediateFile(op_code,"0"+convert_instance.getBitCode(parameter,10), "A") == 0){
                   return 2000;//fatal error more than 1024 memory words.                
                }
                return 50;
            }
        }else if(parameter_info.contentEquals("rlabel")){
            String try1 = sub_process_instance.check_1(parameter);
            if(try1.compareTo("1000")==0 || try1.compareTo("2000")==0 || try1.compareTo("50")==0){
                return Integer.parseInt(try1);
            }
            if(try1.compareTo("0")!=0){
                if(table_instance.addToIntermediateFile(op_code,try1, "A") == 0){
                   return 2000;//fatal error more than 1024 memory words.
                }
                return 50;
            }
            
            String try2 = sub_process_instance.check_2(parameter);
            if(try2.compareTo("1000")==0 || try2.compareTo("2000")==0 || try2.compareTo("50")==0){
                return Integer.parseInt(try2);
            }
            if(try2.compareTo("0")!=0){
                if(table_instance.addToIntermediateFile(op_code,try2, "A") == 0){
                   return 2000;//fatal error more than 1024 memory words.
                }
                return 50;
            }
            int try3 = sub_process_instance.check_3(op_code, parameter);
            //if(try3.compareTo("1000")==0 || try3.compareTo("2000")==0 || try3.compareTo("50")==0){
                return try3;
            //}
            /*if(try3.compareTo("0")!=0){
                if(table_instance.addToIntermediateFile(op_code,try3, "A") == 0){
                   return 2000;//fatal error more than 1024 memory words.
                }
                return 50;
            }*/
        }else if(parameter_info.contentEquals("memoryaddress")){
            String try1 = sub_process_instance.check_1(parameter);
            if(try1.compareTo("1000")==0 || try1.compareTo("2000")==0 || try1.compareTo("50")==0){
                return Integer.parseInt(try1);
            }
            if(try1.compareTo("0")!=0){
                if(table_instance.addToIntermediateFile(op_code,try1, "A") == 0){
                   return 2000;//fatal error more than 1024 memory words.
                }
                return 50;
            }
            
            int try3 = sub_process_instance.check_3(op_code,parameter);
            //if(try3.compareTo("1000")==0 || try3.compareTo("2000")==0 || try3.compareTo("50")==0){
                return try3;
            /*}
            if(try3.compareTo("0")!=0){
                if(table_instance.addToIntermediateFile(op_code,try3, "A") == 0){
                   return 2000;//fatal error more than 1024 memory words.                
                }
                return 50;
            }*/
        }else{
            System.out.println("Some unexpected type entered in MOT");
        }
        
        return 0;
    }
}
